package org.yray.sip.factory;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Component;
import org.yray.sip.factory.inet.IMediaFactory;
import org.yray.sip.rtp.data.MediaClient;
import org.yray.sip.rtp.data.MediaContext;
import org.yray.sip.rtp.dtmf.DtmfContext;
import org.yray.sip.rtp.sender.ISipSessionCache;
import org.yray.sip.server.SipServerContext;
import org.yray.sip.server.SipSession;
import org.yray.sip.utils.ByteUtils;
import org.yray.sip.utils.IcspBeanHolder;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Optional;

@Slf4j
@Component
public class MediaFactory implements IMediaFactory {

    @Override
    public  void addToManData(MediaContext mediaContext, byte[] bs, String callId) {
        if(bs.length== MediaClient.PCMA_SISE+12) {
            byte[] addData = new byte[MediaClient.PCMA_SISE];
            System.arraycopy(bs, 12, addData, 0, MediaClient.PCMA_SISE);
            ByteArrayOutputStream baos = mediaContext.getToManMediaMap().computeIfAbsent(callId, m -> new ByteArrayOutputStream());
            try {
                baos.write(addData);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        else
        {
            log.debug("callId={},type={},RTPBYTESTREAM={}",callId, ByteUtils.uBytes2Int(bs[0],bs[1]), HexUtil.encodeHexStr(bs));
            //0x8065,0x80e5
            //long time=ByteUtils.uBytes2Long(bs[4],bs[5],bs[6],bs[7]);键盘事件
            if(ByteUtils.uBytes2Int(bs[0],bs[1])==0x80e5)
            {
                DtmfContext.putDtmf(callId,bs);
            }
        }
    }

    @Override
    public  void addData(MediaContext mediaContext, byte[] bs)
    {
        //这里主要缓存下媒体流，用于生成录音
        Long ssrc= ByteUtils.uBytes2IntSip(new byte[]{bs[8],bs[9],bs[10],bs[11]});
        MediaClient mediaClient=mediaContext.getMediaClientMap().get(ssrc);
        int currSeq= ByteUtils.uBytes2Int(bs[2],bs[3]);
        if(mediaClient==null)
        {
            mediaClient=  createMediaClient(mediaContext,ssrc,currSeq);

        }
        mediaClient.addPatchDate(bs);
    }

    /***
     *
     * @param ssrc
     * @return
     */
    private  MediaClient createMediaClient(MediaContext mediaContext,Long ssrc,int currSeq)
    {
        log.info("createMediaClient start,ssrc={},currSeq={}",ssrc,currSeq);
        MediaClient mediaClient=mediaContext.getMediaClientMap().computeIfAbsent(ssrc,
                m->new MediaClient(ssrc, IcspBeanHolder.getBean(ISipSessionCache.class).getCallIdBySsrc(ssrc)));
        mediaClient.setBeginSeq(currSeq);
        log.info("createMediaClient end,ssrc={},currSeq={}",ssrc,currSeq);
        return mediaClient;
    }

    public  byte[] getData(MediaContext mediaContext,String ssrc,int step)
    {
        MediaClient mediaClient=mediaContext.getMediaClientMap().get(ssrc);
        if(mediaClient==null)
        {
            log.error("mediaClient is null,ssrc={},step={}",ssrc,step);
            return null;
        }
        return mediaClient.getDataByStep(step);
    }



    @Override
    public  void cleanMediaClient(MediaContext mediaContext, SipSession sipSession)
    {
        Optional.ofNullable(sipSession.getSideSsrc()).ifPresent((v)->{
            mediaContext.getMediaClientMap().remove(v);
        });

    }

    public  MediaClient getMediaClient(MediaContext mediaContext,String ssrc)
    {
        return mediaContext.getMediaClientMap().get(ssrc);
    }

    @Override
    public String createRecordB(SipServerContext sipServerContext, final SipSession sipSession)
    {
        return getFileName(sipServerContext,sipSession);
    }

    @Override
    public String createRecord(SipServerContext sipServerContext, final SipSession sipSession) {
        Long sideSsrc=sipSession.getSideSsrc();
        log.info("createRecord,sidessrc={}",sideSsrc,sipSession.getCallId());
        if(sideSsrc==null)
        {
            log.info("sipSession={},ssrc is null no record to save", JSON.toJSONString(sipSession));
            return null;
        }
        MediaContext mediaContext=sipServerContext.getMediaContext();
        MediaClient mediaClient=mediaContext.getMediaClientMap().get(sideSsrc);
        if(mediaClient!=null)
        {
            //生成录音
            synchronized (sipSession) {
                if (mediaClient != null) {
                    String fileName=getFileName(sipServerContext,sipSession);
                    if(!FileUtil.exist(fileName))
                    {
                        mediaClient.saveToFile(fileName);
                    }
                    sipSession.setFileName(fileName);
                    return fileName;
                }
            }

        }
        else {
            log.info("mediaClient is null ,ssrc",sideSsrc);
        }
        return null;

    }

    private String getFileName(SipServerContext sipServerContext, SipSession sipSession)
    {
        String day = DateUtil.date(sipSession.getSendRRTime()).toDateStr();
        File dayPath = new File(sipServerContext.getFilePath() + File.separator + day);
        try {
            FileUtils.forceMkdir(dayPath);
        } catch (IOException e) {
            log.error("Exception:{}", ExceptionUtils.getStackTrace(e));
        }
        String fileName = dayPath.getPath() + File.separator + sipSession.getCallId() + ".wav";
        return fileName;
    }
}
